package cn.cool.middleware.biz_exception_retry.config.registry;

import cn.cool.middleware.biz_exception_retry.types.exception.BizExceptionRetryException;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.json.JSONUtil;
import lombok.AllArgsConstructor;
import lombok.Data;

import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Bean 方法注册器，支持精确方法查找
 * 结构：Map<类名，Map<方法签名，MethodInfo>>
 *      方法签名格式：methodName(参数的类型列表)
 */
public class BeanMethodRegistry {

    private final Map<String, Map<String, MethodInfo>> classMethodMap = new ConcurrentHashMap<>();

    @Data
    @AllArgsConstructor
    public static class MethodInfo {
        private final Object bean;

        private final Method method;
    }

    /**
     * 注册方法
     * @param bean Spring Bean实例
     * @param method 要注册的方法
     */
    public void registerMethod(Object bean, Method method) {
        // Map<com.example.springdemo.retry.RetryService, Map<retry(int,String), (bean, retry)>>
        String beanName = bean.getClass().getName();
        String methodSignature = createMethodSignature(method);
        // Map<方法签名，MethodInfo>
        classMethodMap.computeIfAbsent(beanName, k -> new ConcurrentHashMap<>())
                .put(methodSignature, new MethodInfo(bean, method));
    }

    /**
     * 根据类名，方法签名找到 <bean, method>
     * @param beanName 类名
     * @param methodSignature 方法签名
     */
    public MethodInfo getMethodInfo(String beanName, String methodSignature) {
        MethodInfo methodInfo = classMethodMap.get(beanName).get(methodSignature);
        if (ObjUtil.isNull(methodInfo)) {
            throw new BizExceptionRetryException("[@BizExceptionRetry] 不存在对应的类或者方法：" + (beanName + ":" + methodSignature));
        }
        return methodInfo;
    }

    /**
     * 构建方法签名
     * @param method 目标方法
     */
    public String createMethodSignature(Method method) {
        return createMethodSignature(method.getName(), method.getParameterTypes());
    }

    /**
     * 创建方法签名
     * @param methodName 方法名
     * @param parameterTypes 方法参数类型
     */
    private String createMethodSignature(String methodName, Class<?>[] parameterTypes) {
        StringBuilder buffer = new StringBuilder(methodName);
        buffer.append("(");

        for (int i = 0; i < parameterTypes.length; i++) {
            if (i > 0) buffer.append(",");
            buffer.append(parameterTypes[i].getSimpleName());
        }

        buffer.append(")");
        return buffer.toString();
    }

    /** 获取所有注册的类名 */
    public Set<String> getAllClassNames() {
        return Collections.unmodifiableSet(classMethodMap.keySet());
    }

    /** 获取指定类的所有方法签名 */
    public Set<String> getMethodSignature(String className) {
        Map<String, MethodInfo> methods = classMethodMap.get(className);
        return methods != null ? Collections.unmodifiableSet(methods.keySet()) : Collections.emptySet();
    }

}
